package rsj.dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rlyy.aibase.db.Dbink;
import com.rlyy.aibase.db.QueryRunner;
import com.rlyy.aibase.utils.base.Box;
import com.rlyy.aibase.utils.base.MapNode;
import com.rlyy.aibase.utils.base.Node;
import com.rlyy.aibase.utils.base.TableNode;
import common.util.Assert;
import common.util.BoxUtil;
import common.util.DateFormat;
import common.util.DateTimeFormatterUtil;
import common.util.http.HttpUtil;
import org.apache.commons.lang3.StringUtils;
import rsj.context.ApplicationContextUtil;
import rsj.db.PostgresqlConn;
import rsj.db.dbutils.UniqueID;
import rsj.domain.TestQueryEntity;
import rsj.domain.TestRemoteParseParameter;
import rsj.job.UpdateTestResult;
import rsj.properties.DataTestProperties;
import rsj.service.test.ITestTemplateMethod;
import rsj.sql.customer.CustomerDao;
import rsj.utils.RedisUtils;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Objects;
import java.util.Optional;

/**
 * @author yuanqinglong
 * @since 2020/10/19 9:35
 */
public class TestLogDao extends BaseDao {

    private static class SingleTestLogDao {
        private static final TestLogDao TEST_LOG_DAO = new TestLogDao();
    }

    public static TestLogDao getInstance() {
        return SingleTestLogDao.TEST_LOG_DAO;
    }

    public int updateTestLogResult(Connection conn, String logId, String result) throws SQLException {
        String updateSql = "UPDATE sys.sys_test_log SET log_result = '" + result + "' WHERE log_id = '" + logId + "'";
        return getQueryRunner().update(conn, updateSql);
    }


    public Box testQuery(Box box, TestQueryEntity testQueryEntity) {
        Box resp;
        if (StringUtils.isBlank(testQueryEntity.getFileId()) || StringUtils.isBlank(testQueryEntity.getProdId())
                || StringUtils.isBlank(testQueryEntity.getAutKeyid()) || StringUtils.isBlank(testQueryEntity.getAutSecretkey())
                || StringUtils.isBlank(testQueryEntity.getAutSignkey())) {
            return BoxUtil.errorBox(box, "参数不足");
        }
        Connection conn = PostgresqlConn.getConnection();
        try {
            MapNode mapNode = getQueryRunner().queryLinkRow(conn, "SELECT prod_uid,prod_id,prod_name,prod_addr FROM sys.sys_prod WHERE prod_id = '" + testQueryEntity.getProdId() + "' ");
            if (mapNode.size() == 0) {
                return BoxUtil.errorBox(box, "产品不存在");
            }
            String tid = box.getNode("$tid");
            String now = LocalDateTime.now().format(DateFormat.DATE_TIME_RIGHT_NEXT_TO);
            String postResult = "{}";
            String downloadFileName = testQueryEntity.getOfflineOrgName() + now + ".zip";
            String generateId = String.valueOf(UniqueID.generateId());
            String taskName = "rsjmq:" + generateId;
            //String orgName = this.queryOrgName(testQueryEntity.getAutKeyid());
            String custSname = this.queryOrgName(testQueryEntity.getAutKeyid());
            String prodAddr = mapNode.getValue("Prod_Addr");
            String prodName = mapNode.getValue("Prod_Name");
            testQueryEntity.setProdName(prodName);
            //调用python接口参数
            DataTestProperties dataTestProperties = ApplicationContextUtil.getApplicationContext().getBean(DataTestProperties.class);
            String pythonTestQueryApi = dataTestProperties.getPythonTestQueryApi();
            Assert.isNotBlank(pythonTestQueryApi,"找不到批量服务测试API");
            TestRemoteParseParameter testRemoteParseParameter =
                    new TestRemoteParseParameter(prodAddr, testQueryEntity.getAutKeyid(), testQueryEntity.getAutSignkey(), testQueryEntity.getFileId(),
                            downloadFileName, taskName, mapNode.getValue("Prod_Uid"));
            this.setRedisTask(taskName);
            String pythonParseFileUrl = dataTestProperties.getPythonTestQueryUrl();
            Assert.isNotBlank(pythonParseFileUrl,"找不到批量服务测试地址");
            postResult = HttpUtil.post(pythonParseFileUrl, createBody(tid, pythonTestQueryApi, testRemoteParseParameter), HttpUtil.createJSONHeader());

            String count = "0";
            // 0=等待中，1=开始任务，2=任务完成，成功，98=任务失败，解析失败，上传原文件、99=任务失败，调用失败，无任何文件上传）
            String result = "0";
            JSONObject pythonResultJson = JSONObject.parseObject(postResult);
            if (Objects.equals(pythonResultJson.getString("$status"), "1")) {
                count = Optional.ofNullable(pythonResultJson.getJSONObject("_data_")).map(jsonObject -> jsonObject.getString("count")).orElse("0");
            }else {
                //失败删除任务
                result = "99";
                RedisUtils.del(taskName);
            }
            testQueryEntity.setOfflineOrgName(custSname);
            resp = saveTestData(box, generateId, testQueryEntity, conn, downloadFileName, downloadFileName, count, result, pythonResultJson);
        } catch (IOException e) {
            return BoxUtil.errorBox(box, "请求超时");
        } finally {
            Dbink.close(conn);
        }
        return resp;
    }


    private void setRedisTask(String taskName) {
        logger.info("保存taskName key：{}", taskName);
        boolean set = RedisUtils.set(taskName, "0", -1);
        logger.info("保存taskName结果：{}", set);
    }


    /**
     * 查询测试机构名称
     *
     * @param autKeyId 机构标记
     * @return 机构名称
     */
    private String queryOrgName(String autKeyId) {
        CustomerDao customerDao = ApplicationContextUtil.getBean(CustomerDao.class);
        ////String sql = " SELECT org_name FROM sys.sys_org  LEFT JOIN sys.sys_authon ON org_id = aut_org_id WHERE aut_keyid = '" + autKeyId + "' ";
        //String sql = "SELECT cust_sname FROM sys.sys_cust LEFT JOIN sys.sys_org ON org_cust_id = cust_id LEFT JOIN sys.sys_authon ON org_id = aut_org_id" +
        //        " WHERE aut_keyid = '" + autKeyId + "' ";
        //Node node = (Node) IExecuteInterface.doExecuteQuery(connection ->
        //                QueryRunnerFactory.getQueryRunner().queryLinkNode(connection, sql)
        //        , e -> logger.error("查询测试机构名称失败,{}", e));
        Node snameByAutKey = customerDao.getCustSnameByAutKey(autKeyId);
        Assert.isNotBlank(snameByAutKey.value(), "机构不存在");
        return snameByAutKey.value();
    }


    public Box saveTestData(Box box, String logId, TestQueryEntity testQueryEntity, Connection conn, String originalId, String sourceFileName, String count, String result, JSONObject pythonResultJson) {

        //保存测试 日志sql
        String sql = String.format("INSERT INTO sys.sys_test_log (log_id,log_org_name,log_prod_id,log_prod_name,log_amount,log_time,log_result," +
                        "log_res_id,log_res_name,log_type) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", "'" + logId + "'", "'" + testQueryEntity.getOfflineOrgName() + "'",
                "'" + testQueryEntity.getProdId() + "'", "'" + testQueryEntity.getProdName() + "'", "'" + count + "'", "TO_TIMESTAMP('" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "', 'YYYY-MM-DD HH24:MI:SS')",
                "'" + result + "'", "'" + originalId + "'", "'" + sourceFileName + "'", "'" + ITestTemplateMethod.DATA_TESTING + "'");
        try {
            //添加测试日志
            getQueryRunner().update(conn, sql);
            if (Objects.equals(pythonResultJson.getString("$status"), "0")) {
                return BoxUtil.errorBox(box, pythonResultJson.getString("$msg"));
            }
            return BoxUtil.successBox(box, "正在解析稍后去报表管理查看结果");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            return BoxUtil.errorBox(box, "测试出错");
        }
    }


    public static String createBody(String tid, String api, Object data) {
        HashMap<String, Object> json = new HashMap<>(8);
        json.put("$tid", tid);
        json.put("$api", api);
        json.put("_data_", data);
        return JSON.toJSONString(json);
    }

    public MapNode getInfoByLogId(String logId) {
        Connection conn = PostgresqlConn.getConnection();
        String sql = "SELECT * FROM sys.sys_test_log WHERE log_id = '" + logId + "'";
        MapNode mapNode;
        try {
            mapNode = getQueryRunner().queryLinkRow(conn, sql);
        } catch (Exception e) {
            return null;
        } finally {
            Dbink.close(conn);
        }
        return mapNode;
    }

    public MapNode getFileInfoByLogId(String logId) {
        Connection conn = PostgresqlConn.getConnection();
        String sql = "SELECT log_res_id,log_res_name,log_par_id,log_par_name FROM sys.sys_test_log WHERE log_id = '" + logId + "'";
        MapNode mapNode;
        try {
            mapNode = getQueryRunner().queryLinkRow(conn, sql);
        } catch (Exception e) {
            return null;
        } finally {
            Dbink.close(conn);
        }
        return mapNode;
    }


    public MapNode testLogList(Connection conn, Integer size, Integer now, String querykey, String startTime, String endTime) {
        QueryRunner queryRunner = new QueryRunner();
        MapNode responsedata = new MapNode();
        StringBuilder countSql = new StringBuilder();
        countSql.append("SELECT COUNT(*) FROM ").append("sys.sys_test_log WHERE log_type = '03'");
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT log_id,log_org_name,log_prod_id,prod_uid,log_prod_name," +
                "log_amount,log_time, log_result,log_res_id,log_par_id FROM sys.sys_test_log LEFT JOIN sys.sys_prod prod ON " +
                " prod.prod_id = log_prod_id WHERE log_type = '03' ");
        if (StringUtils.isNotBlank(querykey)) {
            sql.append(" AND log_org_name LIKE ").append("'%").append(querykey).append("%'");
            countSql.append(" AND log_org_name LIKE ").append("'%").append(querykey).append("%'");
        }
        if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
            LocalDate date = DateTimeFormatterUtil.stringDateToLocalDate(startTime);
            LocalDate endDate = DateTimeFormatterUtil.stringDateToLocalDate(endTime);
            sql.append(" AND log_time >= '").append(date).append("'");
            countSql.append(" AND log_time >= '").append(date).append("'");
            if (Objects.equals(startTime, endTime)) {
                endDate = endDate.plusDays(1);
            }
            sql.append(" AND log_time < '").append(endDate).append("'");
            countSql.append(" AND log_time < '").append(endDate).append("'");
        }
        Node node = queryRunner.queryLinkNode(conn, countSql.toString());
        int count = node.valueInt();
        responsedata.putNode("test_Count", String.valueOf(count));
        if (count == 0) {
            responsedata.putNode("__testLogList__", "");
            return responsedata;
        }
        sql.append(" ORDER BY log_time DESC ");
        if (size != null && now != null) {
            sql.append(" LIMIT ").append(size).append(" OFFSET ").append(size * (now - 1));
        }
        TableNode tableNode = queryRunner.queryLinkTableNode(conn, sql.toString());
        UpdateTestResult updateTestResult = ApplicationContextUtil.getApplicationContext().getBean(UpdateTestResult.class);
        updateTestResult.queryTodayTestData(tableNode);
        responsedata.putNode("__testLogList__", tableNode.toJson());
        return responsedata;
    }


}
